package com.sinnatec.crypto.sm3;

import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;

public class SM3Util {
    private SM3Util(){

    }

    /**
     * 加密
     *
     * @param data 明文
     * @param key 密钥
     * @return
     * @throws Exception
     */
    public static String digest(String data, String key) throws Exception {
        return Base64.getEncoder().encodeToString(getEncryptByKey(data, key));
    }

    /**
     * SM3加密方式之：不提供密钥的方式 SM3加密，返回加密后长度为64位的16进制字符串
     *
     * @param data 明文
     * @return
     */
    public static String digest(String data) {
        return Base64.getEncoder().encodeToString(getEncryptBySrcByte(data.getBytes()));
    }
    /**
     * 利用源数据+密钥校验与密文是否一致
     *
     * @param data       源数据
     * @param key       密钥
     * @param digest 密文
     * @return
     * @throws Exception
     */
    public static boolean verify(String data, String key, String digest) throws Exception {
        byte[] sm3HashCode = Base64.getDecoder().decode(digest);
        byte[] newHashCode = getEncryptByKey(data, key);
        return Arrays.equals(newHashCode, sm3HashCode);
    }

    /**
     * 校验源数据与加密数据是否一致
     *
     * @param src       源数据
     * @param digest 16进制的加密数据
     * @return
     * @throws Exception
     */
    public static boolean verify(String src, String digest) throws Exception {
        byte[] sm3HashCode = Base64.getDecoder().decode(digest);
        byte[] newHashCode = getEncryptBySrcByte(src.getBytes(StandardCharsets.UTF_8));
        return Arrays.equals(newHashCode, sm3HashCode);
    }


    /**
     * SM3加密方式之： 根据自定义密钥进行加密，返回加密后长度为32位的16进制字符串
     *
     * @param src 源数据
     * @param key 密钥
     * @return
     * @throws Exception
     */
    private static byte[] getEncryptByKey(String src, String key) throws Exception {
        byte[] srcByte = src.getBytes(StandardCharsets.UTF_8);
        byte[] keyByte = key.getBytes(StandardCharsets.UTF_8);
        KeyParameter keyParameter = new KeyParameter(keyByte);
        SM3Digest sm3 = new SM3Digest();
        HMac hMac = new HMac(sm3);
        hMac.init(keyParameter);
        hMac.update(srcByte, 0, srcByte.length);
        byte[] result = new byte[hMac.getMacSize()];
        hMac.doFinal(result, 0);
        return result;
    }

    /**
     * 返回长度为32位的加密后的byte数组
     *
     * @param srcByte
     * @return
     */
    private static byte[] getEncryptBySrcByte(byte[] srcByte) {
        SM3Digest sm3 = new SM3Digest();
        sm3.update(srcByte, 0, srcByte.length);
        byte[] encryptByte = new byte[sm3.getDigestSize()];
        sm3.doFinal(encryptByte, 0);
        return encryptByte;
    }

}
